package com.sun.lib;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.ImageView;

/*
 * Created by Administrator on 2019/5/14.
 *
 * #                                                   #
 * #                       _oo0oo_                     #
 * #                      o8888888o                    #
 * #                      88" . "88                    #
 * #                      (| -_- |)                    #
 * #                      0\  =  /0                    #
 * #                    ___/`---'\___                  #
 * #                  .' \\|     |# '.                 #
 * #                 / \\|||  :  |||# \                #
 * #                / _||||| -:- |||||- \              #
 * #               |   | \\\  -  #/ |   |              #
 * #               | \_|  ''\---/''  |_/ |             #
 * #               \  .-\__  '-'  ___/-. /             #
 * #             ___'. .'  /--.--\  `. .'___           #
 * #          ."" '<  `.___\_<|>_/___.' >' "".         #
 * #         | | :  `- \`.;`\ _ /`;.`/ - ` : | |       #
 * #         \  \ `_.   \_ __\ /__ _/   .-` /  /       #
 * #     =====`-.____`.___ \_____/___.-`___.-'=====    #
 * #                       `=---='                     #
 * #     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   #
 * #                                                   #
 * #               佛祖保佑         永无BUG              #
 * #                                                   #
 */
public class SImageViewHelper {
    private ImageView mView;

    //corner
    private float mCornerRadius;
    private float mCornerRadiusTL;
    private float mCornerRadiusTR;
    private float mCornerRadiusBL;
    private float mCornerRadiusBR;
    private float mCornerBorderRadii[] = new float[8];
    private float mCornerBitmapRadii[] = new float[8];

    //Border
    private float mBorderWidth = 0;
    private int mBorderColor;

    private Drawable mIconNormal;
    private Drawable mIconSelected;
    private Drawable mIconUnable;

    private boolean isCircle;
    private Paint mPaint;
    private Paint mStrokePaint;

    private final RectF mDrawableRect = new RectF();
    private final RectF mBorderRect = new RectF();
    private Matrix mDrawMatrix = new Matrix(); // 图片内容位置调整使用
    private Matrix mMatrix = new Matrix(); // 图片位置调整使用

    private int[][] states = new int[3][];
    private StateListDrawable mStateDrawable;

    private boolean isNormal = true;

    public SImageViewHelper(Context context, ImageView mView, AttributeSet attrs) {
        this.mView = mView;
        initAttributeSet(context, attrs);
    }

    private void initAttributeSet(Context context, AttributeSet attrs) {
        if (context == null || attrs == null) {
            setup();
            return;
        }

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SImageView);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mIconNormal = array.getDrawable(R.styleable.SImageView_icon_src);
            mIconUnable = array.getDrawable(R.styleable.SImageView_icon_src_unable);
            mIconSelected = array.getDrawable(R.styleable.SImageView_icon_src_selected);
        } else {
            int normalId = array.getResourceId(R.styleable.SImageView_icon_src, -1);
            int unableId = array.getResourceId(R.styleable.SImageView_icon_src_unable, -1);
            int selectId = array.getResourceId(R.styleable.SImageView_icon_src_selected, -1);
            if (normalId != -1)
                mIconNormal = context.getResources().getDrawable(normalId);
            if (selectId != -1)
                mIconSelected = context.getResources().getDrawable(selectId);
            if (unableId != -1)
                mIconUnable = context.getResources().getDrawable(unableId);
        }

        isCircle = array.getBoolean(R.styleable.SImageView_isCircle, false);
        mCornerRadius = array.getDimensionPixelSize(R.styleable.SImageView_corner_radius, -1);
        mCornerRadiusTL = array.getDimensionPixelSize(R.styleable.SImageView_corner_radius_TL, 0);
        mCornerRadiusTR = array.getDimensionPixelSize(R.styleable.SImageView_corner_radius_TR, 0);
        mCornerRadiusBL = array.getDimensionPixelSize(R.styleable.SImageView_corner_radius_BL, 0);
        mCornerRadiusBR = array.getDimensionPixelSize(R.styleable.SImageView_corner_radius_BR, 0);

        //border
        mBorderWidth = array.getDimension(R.styleable.SImageView_border_width, 0);
        mBorderColor = array.getColor(R.styleable.SImageView_border_color, Color.TRANSPARENT);

        array.recycle();

        if (mIconNormal == null)
            mIconNormal = mView.getDrawable();

        init();
        setup();
    }

    private void init() {
        updateCornersBorderRadii();
        updateCornersBitmapRadii();
        if (mBorderWidth > 0 || isRound())
            isNormal = false;

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mStrokePaint = new Paint();
        mStrokePaint.setAntiAlias(true);
        mStrokePaint.setStyle(Paint.Style.STROKE);
    }

    private void setup() {
        mStateDrawable = new StateListDrawable();
        if (mIconUnable == null)
            mIconUnable = mIconNormal;
        if (mIconSelected == null)
            mIconSelected = mIconNormal;

        states[0] = new int[]{android.R.attr.state_enabled, android.R.attr.state_selected};
        states[1] = new int[]{-android.R.attr.state_enabled};
        states[2] = new int[]{android.R.attr.state_enabled};

        mStateDrawable.addState(states[0], mIconSelected);
        mStateDrawable.addState(states[1], mIconUnable);
        mStateDrawable.addState(states[2], mIconNormal);

        setIcon();
    }

    private void setIcon() {
        mView.setImageDrawable(mStateDrawable);
        mView.invalidate();
    }

    public void onDraw(Canvas canvas) {
        updateCornersBitmapRadii();
        updateDrawableAndrBorderRect();

        drawBitmap(canvas);
        drawBorder(canvas);
    }

    private void drawBitmap(Canvas canvas) {
        if (mView.getDrawable() != null) {

            if (isRound() || isCircle) {
                int layId = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);
                //绘制圆形、圆角图片
                Bitmap dst = makeDst(getWidth(), getHeight());
                Bitmap src = makeSrc(mView.getDrawable(), (int) getDrawWidth(), (int) getDrawHeight());
                canvas.drawBitmap(dst, 0, 0, mPaint);
                mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
                if (mBorderWidth > 0) {
                    mMatrix.setTranslate(mBorderWidth, mBorderWidth);
                }
                canvas.concat(mMatrix);
                canvas.drawBitmap(src, 0, 0, mPaint);
                mPaint.setXfermode(null);
                canvas.restoreToCount(layId);
            } else {
                int saveCount = canvas.getSaveCount();
                canvas.save();
                Drawable drawable = mView.getDrawable();
                updateRoundBounds(drawable);
                if (mBorderWidth > 0) {
                    canvas.translate(mBorderWidth, mBorderWidth);
                }
                if (mDrawMatrix != null) canvas.concat(mDrawMatrix);
                drawable.draw(canvas);
                canvas.restoreToCount(saveCount);
            }
        }
    }

    // 生成图片
    private Bitmap makeSrc(Drawable drawable, int width, int height) {
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        int dWidth = drawable.getIntrinsicWidth();
        int dHeight = drawable.getIntrinsicHeight();

        /*float scale = Math.max(width * 1.0f / dWidth, height * 1.0f / dHeight);
        drawable.setBounds(0, 0, (int) (scale * dWidth), (int) (scale * dHeight));*/
        updateRoundBounds(drawable);
        if (mDrawMatrix != null) canvas.concat(mDrawMatrix);
        drawable.draw(canvas);
        return bitmap;
    }

    private Bitmap makeDst(int width, int height) {
        if (isCircle) {
            return makeDstCircle(width, height, mDrawableRect);
        } else {
            return makeDstRound(width, height, mDrawableRect, mCornerBitmapRadii);
        }
    }

    /**
     * 获取目标资源bitmap 圆角
     *
     * @param width
     * @param height
     * @param rect
     * @param radii
     * @return
     */
    private Bitmap makeDstRound(int width, int height, RectF rect, float[] radii) {
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Path path = new Path();
        path.addRoundRect(rect, radii, Path.Direction.CW);
        canvas.drawPath(path, paint);
        return bitmap;
    }

    /**
     * 获取目标资源
     *
     * @param width
     * @param height
     * @param rect
     * @return
     */
    private Bitmap makeDstCircle(int width, int height, RectF rect) {
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.GREEN);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, Math.min(rect.width() / 2, rect.height() / 2), paint);
        return bitmap;
    }

    private void updateDrawableAndrBorderRect() {
        float half = mBorderWidth / 2f;
        if (isCircle) {   //圆形
            mBorderRect.set(0, 0, getWidth(), getHeight());
            mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);
        } else {
            mBorderRect.set(half, half, getWidth() - half, getHeight() - half);
            mDrawableRect.set(mBorderRect.left + half, mBorderRect.top + half, mBorderRect.right - half, mBorderRect.bottom - half);
        }
    }

    private void drawBorder(Canvas canvas) {
        if (mBorderWidth > 0) {
            mStrokePaint.setColor(mBorderColor);
            mStrokePaint.setStrokeWidth(mBorderWidth);
            if (isCircle) {
                float borderRadiusX = (mBorderRect.width() - mBorderWidth) / 2;
                float borderRadiusY = (mBorderRect.height() - mBorderWidth) / 2;
                canvas.drawCircle(getWidth() / 2, getHeight() / 2, Math.min(borderRadiusX, borderRadiusY), mStrokePaint);
            } else {
                updateCornersBorderRadii();
                Path path = new Path();
                if (isRound()) { //mCornerRadius > 0
                    path.addRoundRect(mBorderRect, mCornerBorderRadii, Path.Direction.CW);
                 //   mStrokePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
                    canvas.drawPath(path, mStrokePaint);
                 //   mStrokePaint.setXfermode(null);
                } else {
                    canvas.drawRect(mBorderRect, mStrokePaint);
                }

            }

        }
    }

    private void updateCornersBitmapRadii() {
        if (mCornerRadius > 0) {
            for (int i = 0; i < mCornerBitmapRadii.length; i++)
                mCornerBitmapRadii[i] = mCornerRadius;
        } else {
            mCornerBitmapRadii[0] = mCornerRadiusTL;
            mCornerBitmapRadii[1] = mCornerRadiusTL;
            mCornerBitmapRadii[2] = mCornerRadiusTR;
            mCornerBitmapRadii[3] = mCornerRadiusTR;
            mCornerBitmapRadii[4] = mCornerRadiusBR;
            mCornerBitmapRadii[5] = mCornerRadiusBR;
            mCornerBitmapRadii[6] = mCornerRadiusBL;
            mCornerBitmapRadii[7] = mCornerRadiusBL;
        }
    }

    private void updateCornersBorderRadii() {
        if (mCornerRadius > 0) {
            for (int i = 0; i < mCornerBorderRadii.length; i++)
                mCornerBorderRadii[i] = mCornerRadius + mBorderWidth * 0.5f;
        } else {
            for (int i = 0; i < mCornerBorderRadii.length; i++)
                mCornerBorderRadii[i] = 0;
            if (mCornerRadiusTL > 0) {
                mCornerBorderRadii[0] += mCornerRadiusTL + mBorderWidth * 0.5f;
                mCornerBorderRadii[1] += mCornerRadiusTL + mBorderWidth * 0.5f;
            }
            if (mCornerRadiusTR > 0) {
                mCornerBorderRadii[2] += mCornerRadiusTR + mBorderWidth * 0.5f;
                mCornerBorderRadii[3] += mCornerRadiusTR + mBorderWidth * 0.5f;
            }
            if (mCornerRadiusBR > 0) {
                mCornerBorderRadii[4] += mCornerRadiusBR + mBorderWidth * 0.5f;
                mCornerBorderRadii[5] += mCornerRadiusBR + mBorderWidth * 0.5f;
            }
            if (mCornerRadiusBL > 0) {
                mCornerBorderRadii[6] += mCornerRadiusBL + mBorderWidth * 0.5f;
                mCornerBorderRadii[7] += mCornerRadiusBL + mBorderWidth * 0.5f;
            }
            /*mCornerBorderRadii[0] = mCornerRadiusTL == 0 ? 0 : mCornerRadiusTL + mBorderWidth / 2f;
            mCornerBorderRadii[1] = mCornerRadiusTL == 0 ? 0 : mCornerRadiusTL + mBorderWidth / 2f;
            mCornerBorderRadii[2] = mCornerRadiusTR == 0 ? 0 : mCornerRadiusTR + mBorderWidth / 2f;
            mCornerBorderRadii[3] = mCornerRadiusTR == 0 ? 0 : mCornerRadiusTR + mBorderWidth / 2f;
            mCornerBorderRadii[4] = mCornerRadiusBR == 0 ? 0 : mCornerRadiusBR + mBorderWidth / 2f;
            mCornerBorderRadii[5] = mCornerRadiusBR == 0 ? 0 : mCornerRadiusBR + mBorderWidth / 2f;
            mCornerBorderRadii[6] = mCornerRadiusBL == 0 ? 0 : mCornerRadiusBL + mBorderWidth / 2f;
            mCornerBorderRadii[7] = mCornerRadiusBL == 0 ? 0 : mCornerRadiusBL + mBorderWidth / 2f;*/
        }
    }

    private void updateRoundBounds(Drawable mDrawable) {
        if (mDrawable == null) return;
        mDrawMatrix = new Matrix();
        final int dwidth = mDrawable.getIntrinsicWidth();
        final int dheight = mDrawable.getIntrinsicHeight();

        final int vwidth = (int) mDrawableRect.width();
        final int vheight = (int) mDrawableRect.height();
        ImageView.ScaleType mScaleType = mView.getScaleType();
        if (dwidth <= 0 || dheight <= 0 || ImageView.ScaleType.FIT_XY == mScaleType) {
            mDrawable.setBounds(0, 0, vwidth, vheight);
        } else {
            mDrawable.setBounds(0, 0, dwidth, dheight);
            if (ImageView.ScaleType.MATRIX == mScaleType) {
                mDrawMatrix = null;
            } else if (ImageView.ScaleType.CENTER == mScaleType) {
                mDrawMatrix.setTranslate(Math.round((vwidth - dwidth) * 0.5f),
                        Math.round((vheight - dheight) * 0.5f));
            } else if (ImageView.ScaleType.CENTER_CROP == mScaleType) {
                float scale;
                float dx = 0, dy = 0;

                if (dwidth * vheight > vwidth * dheight) {
                    scale = (float) vheight / (float) dheight;
                    dx = (vwidth - dwidth * scale) * 0.5f;
                } else {
                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * 0.5f;
                }

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(Math.round(dx), Math.round(dy));
            } else {
                RectF mTempSrc = new RectF();
                RectF mTempDst = new RectF();
                mTempSrc.set(0, 0, dwidth, dheight);
                mTempDst.set(0, 0, vwidth, vheight);
                mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
            }
        }
    }

    private void updateBounds(Drawable mDrawable) {
        if (mDrawable == null) return;
        final int dwidth = mDrawable.getIntrinsicWidth();
        final int dheight = mDrawable.getIntrinsicHeight();

        final int vwidth = (int) mDrawableRect.width();
        final int vheight = (int) mDrawableRect.height();
        ImageView.ScaleType mScaleType = mView.getScaleType();

        final boolean fits = (dwidth < 0 || vwidth == dwidth)
                && (dheight < 0 || vheight == dheight);

        if (dwidth <= 0 || dheight <= 0 || ImageView.ScaleType.FIT_XY == mScaleType) {
            /* If the drawable has no intrinsic size, or we're told to
                scaletofit, then we just fill our entire view.
            */
            mDrawable.setBounds(0, 0, vwidth, vheight);
            mDrawMatrix = null;
        } else {
            // We need to do the scaling ourself, so have the drawable
            // use its native size.
            mDrawable.setBounds(0, 0, dwidth, dheight);

            if (ImageView.ScaleType.MATRIX == mScaleType) {
                if (mMatrix.isIdentity()) {
                    mDrawMatrix = null;
                } else {
                    mDrawMatrix = mMatrix;
                }
            } else if (fits) {
                // The bitmap fits exactly, no transform needed.
                mDrawMatrix = null;
            } else if (ImageView.ScaleType.CENTER == mScaleType) {
                // Center bitmap in view, no scaling.
                mDrawMatrix = mMatrix;
                mDrawMatrix.setTranslate(Math.round((vwidth - dwidth) * 0.5f),
                        Math.round((vheight - dheight) * 0.5f));
            } else if (ImageView.ScaleType.CENTER_CROP == mScaleType) {
                mDrawMatrix = mMatrix;

                float scale;
                float dx = 0, dy = 0;

                if (dwidth * vheight > vwidth * dheight) {
                    scale = (float) vheight / (float) dheight;
                    dx = (vwidth - dwidth * scale) * 0.5f;
                } else {
                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * 0.5f;
                }

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(Math.round(dx), Math.round(dy));
            } else if (ImageView.ScaleType.CENTER_INSIDE == mScaleType) {
                mDrawMatrix = mMatrix;
                float scale;
                float dx;
                float dy;

                if (dwidth <= vwidth && dheight <= vheight) {
                    scale = 1.0f;
                } else {
                    scale = Math.min((float) vwidth / (float) dwidth,
                            (float) vheight / (float) dheight);
                }

                dx = Math.round((vwidth - dwidth * scale) * 0.5f);
                dy = Math.round((vheight - dheight * scale) * 0.5f);

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(dx, dy);
            } else {
                // Generate the required transform.
                RectF mTempSrc = new RectF();
                RectF mTempDst = new RectF();
                mTempSrc.set(0, 0, dwidth, dheight);
                mTempDst.set(0, 0, vwidth, vheight);

                mDrawMatrix = mMatrix;
                //   matrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
            }
        }
    }

    private Matrix.ScaleToFit scaleTypeToScaleToFit(ImageView.ScaleType scaleType) {
        switch (scaleType) {
            case FIT_XY:
                return Matrix.ScaleToFit.FILL;
            case FIT_START:
                return Matrix.ScaleToFit.START;
            case FIT_END:
                return Matrix.ScaleToFit.END;
            default:
                return Matrix.ScaleToFit.CENTER;
        }
    }

    private int getWidth() {
        return mView.getWidth();
    }

    private float getDrawWidth() {
        return mDrawableRect.width();
    }

    private float getDrawHeight() {
        return mDrawableRect.height();
    }

    private int getHeight() {
        return mView.getHeight();
    }

    private void invalidate() {
        mView.invalidate();
    }

    public boolean isNormal() {
        return isNormal;
    }

    public boolean isRound() {
        return isCircle || mCornerRadius > 0 || mCornerRadiusTL > 0 || mCornerRadiusTR > 0 || mCornerRadiusBL > 0 || mCornerRadiusBR > 0;
    }


    public SImageViewHelper setCornerRadius(int radius) {
        this.mCornerRadius = radius;
        init();
        invalidate();
        return this;
    }

    public SImageViewHelper setCornerRadius(float topLeft, float topRight, float bottomLeft, float bottomRight) {
        this.mCornerRadius = -1;
        this.mCornerRadiusTL = topLeft;
        this.mCornerRadiusTR = topRight;
        this.mCornerRadiusBL = bottomLeft;
        this.mCornerRadiusBR = bottomRight;
        init();
        invalidate();
        return this;
    }

    public SImageViewHelper setCornerTopLeft(float cornerTopLeft) {
        this.mCornerRadius = -1;
        this.mCornerRadiusTL = cornerTopLeft;
        init();
        invalidate();
        return this;
    }

    public SImageViewHelper setCornerTopRight(float cornerTopRight) {
        this.mCornerRadius = -1;
        this.mCornerRadiusTR = cornerTopRight;
        init();
        invalidate();
        return this;
    }

    public SImageViewHelper setCornerBottomLeft(float cornerBottomLeft) {
        this.mCornerRadius = -1;
        this.mCornerRadiusBL = cornerBottomLeft;
        init();
        invalidate();
        return this;
    }

    public SImageViewHelper setCornerBottomRight(float cornerBottomRight) {
        this.mCornerRadius = -1;
        this.mCornerRadiusBR = cornerBottomRight;
        init();
        invalidate();
        return this;
    }

    public SImageViewHelper setBorderWidth(int borderWidth) {
        this.mBorderWidth = borderWidth;
        invalidate();
        return this;
    }

    public SImageViewHelper setBorderColor(int color) {
        this.mBorderColor = color;
        invalidate();
        return this;
    }
}
